﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using HtmlAgilityPack;
using Microsoft.Win32;
using HtmlDocument = HtmlAgilityPack.HtmlDocument;

namespace WebCrawlerHelper.Controllers
{
    public class HtmlController
    {
        /// <summary>
        /// utf8编码
        /// </summary>
        /// <param name="strOrignal"></param>
        /// <returns></returns>
        public static string UrlUtf8Encode(string strOrignal)
        {
            StringBuilder sb = new StringBuilder();
            byte[] byStr = Encoding.UTF8.GetBytes(strOrignal);
            for (int i = 0; i < byStr.Length; i++)
            {
                sb.Append(@"%" + Convert.ToString(byStr[i], 16));
            }

            return sb.ToString();
        }

        /// <summary>
        /// 获取html
        /// </summary>
        /// <param name="url"></param>
        /// <param name="enconding"></param>
        /// <returns></returns>
        public static string GetHtmlStr(string url, Encoding enconding)
        {
            try
            {
                WebRequest rGet = WebRequest.Create(url);
                WebResponse rSet = rGet.GetResponse();
                Stream s = rSet.GetResponseStream();
                StreamReader reader = new StreamReader(s, enconding);
                return reader.ReadToEnd();
            }
            catch (WebException)
            {
                //连接失败
                return null;
            }
        }

        /// <summary>
        /// 获取html文件
        /// </summary>
        /// <param name="strHtml"></param>
        /// <returns></returns>
        public static HtmlDocument GetHtmlDocument(string strHtml)
        {
            HtmlDocument doc = new HtmlDocument();
            doc.LoadHtml(strHtml);
            return doc;
        }

        /// <summary>
        /// 获取目标节点
        /// </summary>
        /// <param name="srcHtmlNode"></param>
        /// <param name="targetNodeName"></param>
        /// <returns></returns>
        public static List<HtmlNode> GetHtmlNodeList(HtmlNode srcHtmlNode, string targetNodeName)
        {
            return srcHtmlNode.Descendants(targetNodeName).ToList();
        }

        public static HtmlNode GetSingleNode(HtmlNode srcHtmlNode, string targetNodeName)
        {
            return srcHtmlNode.SelectSingleNode(targetNodeName);
        }

        public static string GetNodeClass(HtmlNode srcHtmlNode)
        {
            return srcHtmlNode.GetAttributeValue("class", "");
        }

        public static string GetNodeHref(HtmlNode srcHtmlNode)
        {
            return srcHtmlNode.GetAttributeValue("href", "");
        }

        public static string GetNodeId(HtmlNode srcHtmlNode)
        {
            return srcHtmlNode.GetAttributeValue("id", "");
        }

        public static string GetNodeName(HtmlNode srcHtmlNode)
        {
            return srcHtmlNode.GetAttributeValue("name", "");
        }

        public static string GetNodeValue(HtmlNode srcHtmlNode)
        {
            return srcHtmlNode.GetAttributeValue("value", "");
        }


        public static string GetDynamicHtml(string url)
        {
            var html = "";
            var webForm = new Form
            {
                WindowState = FormWindowState.Minimized,
                Visible = false,
                ShowInTaskbar = false
            };
            var webBrowser = new WebBrowser();
            webForm.Controls.Add(webBrowser);
            //SetFeatureBrowserEmulation();
            webForm.Load += async (s, e) =>
            {
                try
                {
                    var cts = new CancellationTokenSource(1000 * 60); // cancel in 60s
                    html = await LoadDynamicPage(webBrowser, url, cts.Token);
                    webForm.Close();
                    webForm = null;
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    if (webForm != null)
                    {
                        webForm.Close();
                        webForm = null;
                    }
                }
            };

            Application.Run(webForm);

            return html;
        }

        private static async Task<string> LoadDynamicPage(WebBrowser webBrowser, string url, CancellationToken token)
        {
            // navigate and await DocumentCompleted
            var tcs = new TaskCompletionSource<bool>();
            WebBrowserDocumentCompletedEventHandler handler = (s, arg) =>
                tcs.TrySetResult(true);

            using (token.Register(() => tcs.TrySetCanceled(), useSynchronizationContext: true))
            {
                webBrowser.DocumentCompleted += handler;
                try
                {
                    webBrowser.Navigate(url);
                    await tcs.Task; // wait for DocumentCompleted
                }
                finally
                {
                    webBrowser.DocumentCompleted -= handler;
                }
            }

            // get the root element
            var documentElement = webBrowser.Document.GetElementsByTagName("html")[0];

            // poll the current HTML for changes asynchronosly
            var html = documentElement.OuterHtml;
            while (true)
            {
                // wait asynchronously, this will throw if cancellation requested
                await Task.Delay(500, token);

                // continue polling if the WebBrowser is still busy
                if (webBrowser.IsBusy)
                    continue;

                var htmlNow = documentElement.OuterHtml;
                if (html == htmlNow)
                    break; // no changes detected, end the poll loop

                html = htmlNow;
            }

            // consider the page fully rendered 
            token.ThrowIfCancellationRequested();
            return html;
        }

        private static void SetFeatureBrowserEmulation()
        {
            if (LicenseManager.UsageMode != LicenseUsageMode.Runtime)
                return;
            var appName = System.IO.Path.GetFileName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
            Registry.SetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION",
                appName, 10000, RegistryValueKind.DWord);
        }









        //public static void InitForm(string url)
        //{
        //    var webForm = new Form
        //    {
        //        WindowState = FormWindowState.Minimized,
        //        Visible = false,
        //        ShowInTaskbar = false
        //    };
        //    var webBrowser = new WebBrowser();
        //    webForm.Controls.Add(webBrowser);
        //    webForm.Load += async (s, e) =>
        //    {
        //        try
        //        {
        //            var cts = new CancellationTokenSource(1000*60); // cancel in 10s
        //            var html = await LoadDynamicPage(webBrowser, url, cts.Token);
        //            Console.WriteLine(html);
        //            webForm.Close();
        //            webForm = null;
        //        }
        //        catch (Exception ex)
        //        {
        //            Console.WriteLine(ex.Message);
        //            if (webForm != null)
        //            {
        //                webForm.Close();
        //                webForm = null;
        //            }
        //        }
        //    };

        //    Application.Run(webForm);
        //}

        //public static async Task<string> LoadDynamicPage(WebBrowser webBrowser, string url, CancellationToken token)
        //{
        //    // navigate and await DocumentCompleted
        //    var tcs = new TaskCompletionSource<bool>();
        //    WebBrowserDocumentCompletedEventHandler handler = (s, arg) =>
        //        tcs.TrySetResult(true);

        //    using (token.Register(() => tcs.TrySetCanceled(), useSynchronizationContext: true))
        //    {
        //        webBrowser.DocumentCompleted += handler;
        //        try
        //        {
        //            webBrowser.Navigate(url);
        //            await tcs.Task; // wait for DocumentCompleted
        //        }
        //        finally
        //        {
        //            webBrowser.DocumentCompleted -= handler;
        //        }
        //    }

        //    // get the root element
        //    var documentElement = webBrowser.Document.GetElementsByTagName("html")[0];

        //    // poll the current HTML for changes asynchronosly
        //    var html = documentElement.OuterHtml;
        //    while (true)
        //    {
        //        // wait asynchronously, this will throw if cancellation requested
        //        await Task.Delay(500, token);

        //        // continue polling if the WebBrowser is still busy
        //        if (webBrowser.IsBusy)
        //            continue;

        //        var htmlNow = documentElement.OuterHtml;
        //        if (html == htmlNow)
        //            break; // no changes detected, end the poll loop

        //        html = htmlNow;
        //    }

        //    // consider the page fully rendered 
        //    token.ThrowIfCancellationRequested();
        //    return html;
        //}

    }
}
